home *** CD-ROM | disk | FTP | other *** search
- /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
- /* VirtualSphere.c
- /*
- /* Implements the Virtual Sphere algorithm for 3D rotation using a 2D input device.
- /* See paper "A Study in Interactive 3-D Rotation Using 2-D Control Devices" by
- /* Michael Chen, S. Joy Mountford and Abigail Sellen published in the ACM Siggraph '88
- /* proceedings (Volume 22, Number 4, August 1988) for more detail. The code here
- /* provides a much simpler implementation than that described in the paper.
- /*
- /* Author: Michael Chen, Human Interface Group / ATG
- /* Copyright © 1987-92 Apple Computer, Inc. All rights reserved.
- /*
- /* Part of Virtual Sphere Sample Code Release v1.0
- /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••*/
-
- #ifndef __VIRTUALSPHERE__
- #include "VirtualSphere.h"
- #endif
-
- /* Local routine */
- static void PointOnUnitSphere (Point p,
- Point cueCenter,
- Integer cueRadius,
- CPoint3D *v);
-
- /*=================================================================================================
- /* VirtualSphere
- /*
- /* Determine the axis and angle of rotation from the last 2 locations of the mouse
- /* relative to the Virtual Sphere cue circle.
- /*-------------------------------------------------------------------------------------------------*/
- pascal void VirtualSphere (Point p,
- Point q,
- Point cueCenter,
- Integer cueRadius,
- CPoint3D *axisOfRotation,
- Real *angleOfRotation)
- {
- CPoint3D pp, qq;
- Real axisLength;
-
- /* Project mouse points to 3D points on the +z hemisphere of a unit sphere. */
- PointOnUnitSphere (p, cueCenter, cueRadius, &pp);
- PointOnUnitSphere (q, cueCenter, cueRadius, &qq);
-
- /* Consider the 2 projected points as vectors from the center of the unit sphere.
- * Compute the axis of rotation by cross product of these vectors. */
- CrossProduct3D (&qq, &pp, axisOfRotation);
-
- /* The angle of rotation is determined from the length of the cross product. */
- axisLength = Length3D (axisOfRotation);
- *angleOfRotation = asin (axisLength);
-
- /* The axis of rotation must be a unit vector, so normalize it. */
- if (*angleOfRotation > 0) {
- axisOfRotation->x /= axisLength;
- axisOfRotation->y /= axisLength;
- axisOfRotation->z /= axisLength;
- }
- }
-
- /*=================================================================================================
- /* PointOnUnitSphere
- /*
- /* Project a 2D point on a circle to a 3D point on the +z hemisphere of a unit sphere.
- /* If the 2D point is outside the circle, it is first mapped to the nearest point on
- /* the circle before projection.
- /* Orthographic projection is used, though technically the field of view of the camera
- /* should be taken into account. However, the discrepancy is neglegible.
- /*-------------------------------------------------------------------------------------------------*/
- static void PointOnUnitSphere (Point p,
- Point cueCenter,
- Integer cueRadius,
- CPoint3D *v)
- {
- Real length;
- Real lengthSqared;
-
- /* Turn the mouse points into vectors relative to the center of the circle
- * and normalize them. Note we need to flip the y value since the 3D coordinate
- * has positive y going up. */
- v->x = (Real) (p.h - cueCenter.h) / (Real) cueRadius;
- v->y = (Real) -(p.v - cueCenter.v) / (Real) cueRadius;
-
- lengthSqared = v->x*v->x + v->y*v->y;
-
- /* Project the point onto the sphere, assuming orthographic projection.
- * Points beyond the virtual sphere are normalized onto
- * edge of the sphere (where z = 0). */
- if (lengthSqared < 1.0) {
- v->z = sqrt (1.0 - lengthSqared);
- } else {
- length = sqrt (lengthSqared);
- v->x /= length;
- v->y /= length;
- v->z = 0.0;
- }
- }
-